// PicoStreamIn.v - a stream coming into the firmware from the Pico bus
// Copyright 2006, Pico Computing, Inc.

//todo: eos
//      some real reset logic, taking different clock domains into account

`include "PicoDefines.v"

module PicoStreamIn #(
   parameter StreamNum  = 10,
   parameter Width      = 32,    //fixed
// parameter Depth      = 4096,  //fixed
   parameter StatusAddr = (`PICO_STREAM_STATUS_BASE + `PICO_STREAM_STATUS_SIZE*(StreamNum-1) + 4),
   parameter DataAddr   = (`PICO_STREAM_BASE + `PICO_STREAM_SIZE*(StreamNum-1))
) (
   input Rst,
   // Pico/Channel bus signals
   input BusClk, input [31:0] BusAddr, input [31:0] BusDataIn, output [31:0] BusDataOut, input BusRead, input BusWrite,
   // Stream signals
   input StreamClk, output [Width-1:0] StreamData, output StreamRdy, input StreamEn, output StreamEOS
);

wire FifoAlmostFull, FifoAlmostEmpty, FifoFull, FifoEmpty;
wire [11:0] FifoReadCount;
wire [11:0] FifoWriteCount;

wire ReadStatusValid      = BusRead  & ({BusAddr[31:2],   2'b0} == StatusAddr);
//making the fifo pointers accessible is temporary. don't depend on it.
wire ReadCountsValid      = BusRead  & ({BusAddr[31:2],   2'b0} == (StatusAddr + 4));
wire WriteDataValid       = BusWrite & ({BusAddr[31:20], 20'h0} == DataAddr);

wire [31:0] ExtraStat     = {4'ha, FifoWriteCount[11:0], FifoEmpty, FifoAlmostEmpty, FifoFull, FifoAlmostFull, FifoReadCount[11:0]};
wire [19:0] FifoFreeCount = {7'h0, ((FifoWriteCount == FifoReadCount) & ~FifoAlmostFull) ? 13'h200 : {1'b0, FifoReadCount[11:0] - FifoWriteCount[11:0]}};
wire [31:0] Status        = {`BM_WRITE_STATUS_SIGNATURE, 6'h0, FifoFreeCount[19:0]};
assign BusDataOut[31:0]   = ReadStatusValid ? Status[31:0] : (ReadCountsValid ? ExtraStat[31:0] : 32'h0);

//Note that due to the latency on FifoFull, we don't see the 'full' signal till it's too late. We're trusting the software...
assign StreamRdy          = ~FifoEmpty;
wire   FifoRead           = StreamRdy & StreamEn;
wire   FifoWrite          = ~FifoFull & WriteDataValid;
assign StreamEOS          = 0;

//Following instantiates a fifo that is reps*4 bits wide and 4096 deep (property of fifo).
FIFO16_REP #(
    .REPS(1),
    .ALMOST_FULL_OFFSET(12'h10),        // Sets almost full threshold
    .ALMOST_EMPTY_OFFSET(12'h10),       // Sets the almost empty threshold
    .DATA_WIDTH(36),                    // Sets data width to 4, 9, 18, or 36
    .FIRST_WORD_FALL_THROUGH("TRUE")    // Sets the FIFO FWFT to "TRUE" or "FALSE"
) F16I (
    .ALMOSTEMPTY(FifoAlmostEmpty),      // 1-bit almost empty output flag
    .ALMOSTFULL(FifoAlmostFull),        // 1-bit almost full output flag
    .DO(StreamData[31:0]),
    //.DOP(),
    .EMPTY(FifoEmpty),
    .FULL(FifoFull),
    .RDCOUNT(FifoReadCount),
    //.RDERR(),
    .WRCOUNT(FifoWriteCount),
    //.WRERR(),
    .DI(BusDataIn[31:0]),
    //.DIP(4'h0),
    .RDCLK(StreamClk),
    .RDEN(FifoRead),
    .RST(Rst),                          // 1-bit reset input
    .WRCLK(BusClk),                     // 1-bit write clock input
    .WREN(FifoWrite)                    // 1-bit write enable input
);

endmodule
